#! /usr/bin/env python
#-*- coding: utf-8 -*-

# Balloon - An alternative to DropBox with file version control.
# It is based on Mercurial and supports Git.
# Copyright (C) 2011  Cédric Bonhomme - http://cedricbonhomme.org/
#
# For more information : http://bitbucket.org/cedricbonhomme/balloon/
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>

__author__ = "Cedric Bonhomme"
__version__ = "$Revision: 0.1 $"
__date__ = "$Date: 2011/10/03 $"
__revision__ = "$Date: 2011/10/31 $"
__copyright__ = "Copyright (c) Cedric Bonhomme"
__license__ = "GPLv3"

import time
import threading

from mercurial import commands
from mercurial import ui, hg


class HgSync(object):
    """
    The class is responsible of the synchronization of a Mercurial repository.
    """
    def __init__(self, repository_name, repository_url, local_url, username):
        """
        """
        self.repository_name = repository_name
        self.repository_url = repository_url
        self.local_url = local_url
        self.username = username

        self.locker = threading.Lock()

        self.nb_commit = 0

        # Clone the remote repository.
        self.clone()

        self.initialize()

        # Create a new thread which will periodically pull changes:
        thread_pull = threading.Thread(None, self.pull_loop, None)
        # Start the new thread:
        thread_pull.setDaemon(True)
        thread_pull.start()

        # Create a new thread which will periodically push changes
        thread_push = threading.Thread(None, self.push_loop, None)
        # Start the new thread:
        thread_push.setDaemon(True)
        thread_push.start()

    def initialize(self):
        """
        Initialize a new repository.
        """
        self.repo = hg.repository(ui.ui(), self.local_url)

    def clone(self):
        """
        Clone an existing repository.
        """
        try:
            commands.clone(ui.ui(), self.repository_url, self.repository_name)
        except Exception, e:
            print e

    def commit(self, message):
        """
        """
        self.locker.acquire()
        commands.commit(self.repo.ui, self.repo, user=self.username , message=message, addremove=True)
        self.nb_commit += 1
        self.locker.release()

    def add(self, new_file):
        """
        Add new_file to the list of tracked files.
        """
        print "add", new_file
        commands.add(self.repo.ui, self.repo, new_file)
        self.commit("Added " + new_file)

    def modify(self, the_file):
        """
        Modify a file.
        """
        self.commit("Updated " + the_file)

    def remove(self, file_to_remove):
        """
        Remove a file.
        """
        print file_to_remove
        commands.remove(self.repo.ui, self.repo, file_to_remove)
        self.commit("Removed " + file_to_remove)

    def rename(self, file_from, file_to):
        """
        Rename a file.
        """
        self.remove(file_from)
        self.add(file_to)
        self.push()

    def push_loop(self):
        """
        Push changes every n commits in order to avoid to avoid a heavy use of the network.
        """
        time.sleep(2)
        while True:
            time.sleep(1)
            if self.nb_commit == 5:
                commands.push(self.repo.ui, self.repo, self.repository_url)
                self.nb_commit = 0

    def push(self):
        """
        Push changes and set the number of commits to zero.
        """
        commands.push(self.repo.ui, self.repo, self.repository_url)
        self.nb_commit = 0

    def pull_loop(self):
        """
        Pull from the remote repository.
        """
        while True:
            commands.pull(self.repo.ui, self.repo)
            commands.update(self.repo.ui, self.repo)
            time.sleep(240)



if __name__ == "__main__":
    # Point of entry in execution mode.
    pass
    repo = HgSync("https://cedricbonhomme@bitbucket.org/cedricbonhomme/test-balloon", ".")
    #repo.initialize()
    repo.clone()